package model.audio;

import java.net.InetSocketAddress;
import java.util.ArrayList;

import model.audio.Interface.AudioStateObservable;
import model.audio.Interface.AudioStateObserver;
import model.audio.Interface.IAudioMixerModel;
import model.audio.Interface.IMixer;

public class AudioMixerModel implements Runnable,IMixer,IAudioMixerModel,AudioStateObservable{

	private ArrayList<Player> players=null;
	private AudioStateObserver asObserver=null;
	private float volume=6.0f;
	private Thread thread;

	public static final float DEFAULT_VOLUME_PERCENT=1.0f;
	
	public AudioMixerModel(){
		players=new ArrayList<Player>();
		thread=new Thread(this);
		thread.start();
	}
	
	public AudioMixerModel(ArrayList<InetSocketAddress> ads){
		players=new ArrayList<Player>();
		for(InetSocketAddress ad:ads){
			Player p=new Player(ad,volume,System.currentTimeMillis());
			players.add(p);
		}
		thread=new Thread(this);
		thread.start();
	}

	@Override
	public void mix(InetSocketAddress ad, byte[] data) {
		// TODO Auto-generated method stub
		updateAudioState(ad);
		if(players!=null){
			for(Player p:players){
				if(p.getClient().equals(ad)){
					p.play(data);
					break;
				}
			}
		}
	}

	private void updateAudioState(InetSocketAddress ad){
		if(asObserver!=null){
			Player player=null;
			for(Player p:players){
				if(p.getClient().getAddress().getHostAddress().equals(ad.getAddress().getHostAddress())){
					player=p;
					break;
				}
			}
			if(player!=null){
				player.audioStartTime=System.currentTimeMillis();
				if(player.isTalk!=true){
					player.isTalk=true;
					asObserver.updateAudioSessionState(player.getClient(), true);
				}
			}
		}
	}
	
	@Override
	public void setVolume(float value) {
		// TODO Auto-generated method stub
		if(value<0){
			value=0;
		}else if(value>1){
			value=1;
		}		
		float range=(float) (Math.pow(10, 3.0/10)-Math.pow(10, -4));
		value= (float) (Math.pow(10, -4)+range*value);
		value=(float) (20*Math.log10(value));    // -80~6
		volume=value;
		for(Player p:players){
			p.setVolume(volume);
		}
	}

	@Override
	public void addObserver(AudioStateObserver asObserver) {
		// TODO Auto-generated method stub
		this.asObserver=asObserver;
	}
	
	@Override
	public void addNewSourceClient(InetSocketAddress ad) {
		// TODO Auto-generated method stub
		Player p=new Player(ad,volume,System.currentTimeMillis());
		players.add(p);
	}

	@Override
	public void removeSourceClient(InetSocketAddress ad) {
		// TODO Auto-generated method stub
		for(Player p:players){
			if(p.getClient().equals(ad)){
				p.close();
				players.remove(p);
				break;
			}
		}
	}

	@Override
	public synchronized void updateSourceClientList(ArrayList<InetSocketAddress> ads) {
		// TODO Auto-generated method stub
		boolean exist;
		for(InetSocketAddress ad:ads){
			exist=false;
			for(int i=0;i<players.size();i++){
				Player p=players.get(i);
				if(p.getClient().equals(ad)){
					exist=true;
					break;
				}
			}
			if(!exist){
				Player player=new Player(ad,volume,System.currentTimeMillis());
				players.add(player);
			}
		}
	}

	//这个线程用来更新语音状态，因为不是通过包中传送信息来判断是不是在讲话，而是通过是不是有包传过来来判断在不在讲话的
	@Override
	public void run() {    //一段时间不传就判断为不在说话
		// TODO Auto-generated method stub
		while(!thread.isInterrupted()){
			
			synchronized (this)
			{
				for(Player p:players){
					if((System.currentTimeMillis()-p.audioStartTime)>AudioCaptureModel.MAX_WAIT_TIME){
						if(p.isTalk!=false){
							p.isTalk=false;
							asObserver.updateAudioSessionState(p.getClient(), false);
						}
					}
				}
			}		
			try {
				Thread.sleep(AudioCaptureModel.MAX_WAIT_TIME);
			} catch (InterruptedException e) {

			}
		}
	}

	@Override
	public void stop() {
		// TODO Auto-generated method stub
		thread.interrupt();
		for(Player p:players){
			p.close();
		}
	}	
	
}
